import streamlit as st
#import vaex
import os
#import matplotlib.pyplot as plt
from pandasql import sqldf

import Config
Config.main()


##################
# 页面设置
st.set_page_config(page_title="多文件全量分析", page_icon="📊")
st.header("多文件全量分析")
st.markdown("什么是 Vaex?")
st.markdown("Vaex是一个高性能的 Python 库，用于替代 pandas，它使用表达式系统和内存映射，允许开发人员在标准机器上对内存不足或大型数据集执行操作。它涵盖了 pandas 的一些 API，并且更侧重于数据探索和可视化。")
st.markdown("Vaex 与 Pandas API 不完全兼容，但大多数数据整理和探索功能也可用于 Vaex。数据集特征的可视化是使用直方图、密度图和 3d 体积渲染完成的。")
st.markdown("Vaex 的效率如何？")
st.markdown("与对大型数据集执行操作相比，Vaex 与 Pandas 相比非常高效。")
st.markdown("* 能够在您的机器上即时读取大约1.2TB的数据。")
st.markdown("* 可以在笔记本电脑上轻松处理和执行超过10 亿行的操作")
st.markdown("* 与 pandas 相比，能够将字符串处理速度提高10-1000 倍。")
st.markdown("Vaex 为何如此高效？")
st.markdown("- Vaex 可以加载非常大的数据集（将近 1.2TB），并且能够在您的机器上执行探索和可视化。Vaex 不是将整个数据加载到内存中，而是只是内存映射数据并创建一个表达系统。")
st.markdown("- Vaex 使用内存映射、零内存复制策略和惰性计算来获得最佳性能，因此不会浪费内存。每次您对数据框进行任何更改时，它实际上都引用相同的数据，它只是向表达式添加一个新状态。")
st.write("*"*10)


##################
# 选项窗口

st.session_state.P03_datafile_info = st.text_input("请输入数据文件夹路径：", value=st.session_state.P03_datafile_info)
if os.path.exists(st.session_state.P03_datafile_info):
    options = os.listdir(st.session_state.P03_datafile_info)
    for op in options:
        file_extension = os.path.splitext(op)[1]
        if file_extension not in ['.txt', '.csv']:
            options.remove(op)
    st.session_state.P03_datafile_name = st.multiselect("请选择数据文件：", options=options)
else:
    st.error("请输入正确的数据文件夹路径")
datafile_paths = []
for file in st.session_state.P03_datafile_name:
    datafile_paths.append(os.path.join(st.session_state.P03_datafile_info, file))

st.session_state.P03_seperator = st.text_input("数据文件分隔符：", value=st.session_state.P03_seperator)
st.session_state.P03_encoding = st.text_input("数据文件编码：", value=st.session_state.P03_encoding)

st.write("*"*10)

##################
# 显示文件信息
st.write(f"当前文件夹路径： {st.session_state.P03_datafile_info}， 数据文件信息如下：")
if len(datafile_paths)>0:
    for datafile_path in datafile_paths:
        st.write(f"数据文件路径： {datafile_path}")
        st.write(f"数据文件大小： {round(os.path.getsize(datafile_path)/1024, 2)}KB / {round(os.path.getsize(datafile_path)/1024/1024, 2)}MB / {round(os.path.getsize(datafile_path)/1024/1024/1024, 2)}GB")



##################
# 加载所有文件
dfnames = []
for datafile_path in datafile_paths:
    dfnames.append(os.path.splitext(os.path.basename(datafile_path))[0])
st.write(f"数据表名： {dfnames}")
st.write("*"*10)
#########################################################################################



def write_excel(df, filepath):
    with pd.ExcelWriter(filepath, engine='openpyxl') as writer:
        df.to_excel(writer, sheet_name='Sheet1', index=False)

def write_csv(df, filepath, sep=',', encoding='utf-8'):
    df.to_csv(filepath, sep=sep, encoding=encoding, index=False)


#########################################################################################
##################
    
# 加载所有文件函数
def load_datafile(datafile_path):
    # 获取文件扩展名
    file_extension = os.path.splitext(datafile_path)[1]
    # 判断文件扩展名
    if file_extension == '.xlsx':
        df = pd.read_excel(datafile_path)
    elif file_extension == '.csv' or file_extension== '.txt':
        df = pd.read_csv(datafile_path)
    else:
        st.write("不支持的文件格式")
        return None
    return df

##################
# 代码加载
code = ''
uploaded_file = st.file_uploader('请选择一个代码文件')
if uploaded_file is not None:
    from io import StringIO
    bytes_data = uploaded_file.getvalue()
    #st.write(bytes_data)
    stringio = StringIO(uploaded_file.getvalue().decode("utf-8"))
    #st.write(stringio)
    string_data = stringio.read()
    #st.write(string_data)    
    #exec(string_data)
    code = string_data

##################
# SQL输入框
# st.session_state.P03_sql = st.text_area("SQL 语句：", value='')
# print(st.session_state.P03_sql)
# sql = st.session_state.P03_sql



# SQL 分析
# 为运行SQL查询定义可重复使用的函数
# query表示想要在Pandas数据帧上执行的SQL查询语句。它应该是一个包含有效SQL查询的字符串。
# globals()指定了查询中使用的数据帧所在的全局命名空间。
# sqldf函数将执行SQL查询，并返回一个Pandas数据帧，其中包含查询结果。
#run_query = lambda query: sqldf(query, globals()) #运行单句sql
def run_query(query):
    run = lambda query: sqldf(query, globals())
    query_list = query.split(';')
    query_list = [q for q in query_list if q.strip() != '']
    result = None
    for q in query_list:
        result = run(q)
    return result


# 运行SQL查询
sep = st.session_state.P03_seperator
encoding = st.session_state.P03_encoding
merged_data = list(zip(dfnames, datafile_paths))

if st.button("运行代码文件、SQL查询"):
    for merge in merged_data:
        dfname, datafile_path = merge
        exec(f'{dfname} = pd.read_csv(datafile_path, sep=sep, encoding=encoding)')
    exec(code)
    result = run_query(sql)
    st.dataframe(result)

if st.button("运行代码文件、SQL查询，并保存到excel文件"):
    for merge in merged_data:
        dfname, datafile_path = merge
        exec(f'{dfname} = pd.read_csv(datafile_path, sep=sep, encoding=encoding)')
    exec(code)
    result = run_query(sql)
    st.dataframe(result.head(100))
    result_file = os.path.join(st.session_state.P03_datafile_info, 'result.xlsx')
    write_excel(result, result_file)
    st.success(f"保存成功:  {result_file}")
